package cn.kgc.vue.service.impl;

import cn.hutool.crypto.digest.MD5;
import cn.kgc.vue.commons.QueryCondition;
import cn.kgc.vue.commons.ResponseResult;
import cn.kgc.vue.entity.Permission;
import cn.kgc.vue.entity.RolePers;
import cn.kgc.vue.entity.User;
import cn.kgc.vue.entity.UserRole;
import cn.kgc.vue.form.LoginFrom;
import cn.kgc.vue.form.PasswordForm;
import cn.kgc.vue.form.UserForm;
import cn.kgc.vue.mapper.*;
import cn.kgc.vue.service.UserService;
import cn.kgc.vue.utils.IpUtil;
import cn.kgc.vue.utils.JWTUtil;
import cn.kgc.vue.utils.SaltUtil;
import cn.kgc.vue.vo.UserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author mengshun
 * @description 针对表【sys_user】的数据库操作Service实现
 * @createDate 2023-12-02 09:43:31
 */
@Service
@Slf4j
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private JWTUtil jwtUtil;

    @Resource
    private DeptMapper deptMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RolePersMapper rolePersMapper;

    @Resource
    private PermissionMapper permissionMapper;

    @Override
    public ResponseResult login(LoginFrom loginFrom, HttpServletRequest request) {

        // 1. 判定验证码
        String redisCode = stringRedisTemplate.opsForValue().get(loginFrom.getImguuid());
        if (StringUtils.isEmpty(redisCode)) {
            return ResponseResult.fail().message("验证码失效,请刷新重试!!!");
        }

        if (!StringUtils.equals(redisCode, loginFrom.getCode())) {
            return ResponseResult.fail().message("验证码错误");
        }
        // 2.判定用户名是否存在
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername, loginFrom.getUsername());
        User user = baseMapper.selectOne(lambda);

        if (ObjectUtils.isNull(user)) {
            throw new UnknownAccountException();
        }

        // 判定用户是否被禁用
        if (user.getState() == 0) {
            throw new LockedAccountException();
        }

        // 3.密码校验
        String MD5Password = user.getPassword();
        String password = loginFrom.getPassword();
        String hex = new Md5Hash(password, user.getSalt(), 1024).toHex();

        if (!StringUtils.equals(MD5Password, hex)) {
            throw new IncorrectCredentialsException();
        }

        // 4. 颁发令牌
        HashMap<String, Object> payload = new HashMap<>();
        payload.put("username", user.getUsername());
        payload.put("uid", user.getId());

        String token = jwtUtil.createToken(payload);


        // 5. token   ip   -> redis   用户注销登录   防止token的盗用   token:ip
        String ip = IpUtil.getIp(request);
        // 摘要算法
        String s = MD5.create().digestHex(token);
        stringRedisTemplate.opsForValue().set(s, ip, 7, TimeUnit.DAYS);

        // 6.响应数据封装  token    nickName用于前端头部信息展示
        HashMap<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("nickName", user.getNickName());

        // 7.将数据响应给前端   ResponseResult
        return ResponseResult.success().message("登录成功").data(result);
    }

    @Override
    public ResponseResult userList(QueryCondition<User> queryCondition) {

        log.debug("queryCondition={}", queryCondition);

        // 分页查询
        Page<User> userPage = new Page<>(queryCondition.getPage(), queryCondition.getLimit());

        // 查询条件
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.like(StringUtils.isNotEmpty(queryCondition.getQuery().getUsername()), User::getUsername, queryCondition.getQuery().getUsername())
                .eq(ObjectUtils.isNotNull(queryCondition.getQuery().getDeptId()), User::getDeptId, queryCondition.getQuery().getDeptId())
                .eq(ObjectUtils.isNotNull(queryCondition.getQuery().getState()), User::getState, queryCondition.getQuery().getState())
                .select(User::getId, User::getUsername, User::getNickName, User::getDeptId, User::getState,
                        User::getCity, User::getCreateTime, User::getSex, User::getTel)
                .orderByDesc(User::getCreateTime);


        baseMapper.selectPage(userPage, lambda);

        List<User> users = userPage.getRecords();

        List<UserVO> userVOS = users.stream().map(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);

            Integer deptId = user.getDeptId();
            // 根据部门id  查询部门名称
            String deptName = deptMapper.selectById(deptId).getDeptName();
            userVO.setDeptName(deptName);

            // 查询用户所有的角色名称
            Integer uid = user.getId();
            QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
            userRoleQueryWrapper.eq("user_id", uid);
            List<Integer> rids = userRoleMapper.selectList(userRoleQueryWrapper).stream().map(ur -> ur.getRoleId()).collect(Collectors.toList());
            List<String> roleNames = roleMapper.selectBatchIds(rids).stream().map(role -> role.getRoleCh()).collect(Collectors.toList());
            userVO.setRoles(roleNames);
            return userVO;
        }).collect(Collectors.toList());

        // 封装响应结果
        HashMap<String, Object> resultData = new HashMap<>();
        resultData.put("pageData", userVOS);
        resultData.put("total", userPage.getTotal());

        return ResponseResult.success().data(resultData);
    }

    @Override
    public ResponseResult batchRemoveByIds(List<Integer> ids) {

        log.debug("========ids:{}========", ids);

        //  删除用户表中的信息
        baseMapper.deleteBatchIds(ids);

        // 删除用户角色关联表中的信息
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.in(UserRole::getUserId, ids);
        userRoleMapper.delete(lambda);

        return ResponseResult.success().message("删除成功");
    }

    @Override
    public ResponseResult saveUser(UserForm userForm) {

        // userForm  ->  user
        User user = new User();
        BeanUtils.copyProperties(userForm, user);
        // 添加user到数据库  用户名 校验唯一性
        String username = user.getUsername();
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername, username);
        User usr = baseMapper.selectOne(lambda);
        if (ObjectUtils.isNotNull(usr)) {
            return ResponseResult.fail().message("用户名已存在");
        }

        String salt = SaltUtil.createSalt(8);
        String hex = new Md5Hash("666666", salt, 1024).toHex();
        user.setSalt(salt);
        user.setPassword(hex);
        baseMapper.insert(user);

        // userForm   ->  roleIds  -> user_role
        Integer uid = user.getId();
        List<Integer> roleIds = userForm.getRoleIds();
        roleIds.forEach(roleId -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(uid);
            userRole.setRoleId(roleId);
            userRoleMapper.insert(userRole);
        });

        return ResponseResult.success().message("添加成功");
    }

    @Override
    public ResponseResult getUserById(Integer uid) {

        UserForm userForm = new UserForm();
        User user = baseMapper.selectById(uid);

        BeanUtils.copyProperties(user, userForm);

        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.eq(UserRole::getUserId, uid);
        List<Integer> roleIds = userRoleMapper.selectList(lambda)
                .stream().map(ur -> ur.getRoleId()).collect(Collectors.toList());
        userForm.setRoleIds(roleIds);


        return ResponseResult.success().data(userForm);
    }

    @Override
    public ResponseResult editUser(UserForm userForm) {

        // userForm  ->  user
        User user = new User();
        BeanUtils.copyProperties(userForm, user);
        baseMapper.updateById(user);

        // userForm   ->  roleIds  -> user_role    1,2,3,4,7   3,4  uid  1.删除用户当前的所有角色   2.将最新的角色信息插入数据
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.eq(UserRole::getUserId, user.getId());
        userRoleMapper.delete(lambda);

        List<Integer> roleIds = userForm.getRoleIds();
        roleIds.forEach(rid -> {
            UserRole userRole = new UserRole();
            userRole.setRoleId(rid);
            userRole.setUserId(user.getId());
            userRoleMapper.insert(userRole);
        });

        return ResponseResult.success().message("修改成功");
    }

    @Override
    public ResponseResult editPersonalPassword(PasswordForm passwordForm, HttpServletRequest request) {

        // 1. 判定原始密码是否正确  明文
        String oldPassword = passwordForm.getOldPassword();
        String token = request.getHeader("token");
        Map<String, Object> claims = jwtUtil.getClaims(token);
        Integer uid = (Integer) claims.get("uid");

        User user = baseMapper.selectById(uid);
        String dataBasePassword = user.getPassword();
        String salt = user.getSalt();
        String userPassword = new Md5Hash(oldPassword, salt, 1024).toHex();

        if (!StringUtils.equals(dataBasePassword, userPassword)) {
            return ResponseResult.fail().message("原始密码不正确");
        }

        // 更新密码
        String newPassword = passwordForm.getNewPassword();
        String salt1 = SaltUtil.createSalt(8);
        String newHex = new Md5Hash(newPassword, salt1, 1024).toHex();

        user.setPassword(newHex);
        user.setSalt(salt1);

        baseMapper.updateById(user);

        return ResponseResult.success().message("密码更新成功");
    }

    @Override
    public ResponseResult getUserPermission(Integer uid) {

        // 1. 根据用户的id  查询角色id  user_role

        List<Integer> rids = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("user_id", uid))
                .stream().map(ur -> ur.getRoleId()).collect(Collectors.toList());

        // 2. 根据角色id  查询权限id    role_permission

        Set<Integer> pIds = rolePersMapper.selectList(new QueryWrapper<RolePers>().in("role_id", rids))
                .stream().map(rolePers -> rolePers.getPerId())
                .collect(Collectors.toSet());

        // 3. 根据权限id  查询权限信息   剔除 按钮权限
        List<Permission> permissions = permissionMapper.selectBatchIds(pIds)
                .stream().filter(permission -> permission.getIsMenu() != 2)
                .collect(Collectors.toList());

        return ResponseResult.success().data(permissions);
    }
}




